

function getFileSha1(file, cb, pgcb, sliceSize) {
  // sha1算法
  var shA1 = sha1.digest,
    prefix = 0x16,
    blockCount = 0,
    sha1String = [],
    blockfile = undefined;
  var blockSize = sliceSize | (4 * 1024 * 1024);

  if (file) {
    let totalsize = file.size;
    blockCount = Math.ceil(totalsize / blockSize);
    //let starttime = Date.now();
    let step =
      blockCount < 21
        ? 1
        : blockCount > 100
        ? blockCount > 500
          ? blockCount > 1000
            ? 23
            : 11
          : 7
        : 3;
    let hashindex = [];
    for (let i = 0; i < blockCount - 1; i += step) {
      hashindex.push(i);
    }
    hashindex.push(blockCount - 1);

    for (let i in hashindex) {
      let reader = new FileReader();
      reader.id = i;
      reader.name = file.name;
      reader.count = hashindex.length;
      reader.start = 0;
      reader.startbt = 0;
      blockfile = file.slice(
        hashindex[i] * blockSize,
        (hashindex[i] + 1) * blockSize
      );
      reader.onload = e => {
        let buffer = e.currentTarget.result;
        sha1String[i] = shA1(buffer);
        if (Object.getOwnPropertyNames(sha1String).length > hashindex.length) {
          //console.log("读取结束",'step:' + step + ' end:' + i,sha1String,(Date.now() - starttime));
          if (cb) {
            cb(calcEtag());
          }
        }
      };
      reader.readAsArrayBuffer(blockfile);
      reader.onloadend = e => {
        if (pgcb) {
          pgcb(e);
        }
      };
      reader.onprogress = progress;
    }
  }

  function progress(evt) {
    if (evt.lengthComputable) {
      //let percentLoaded = (evt.loaded / evt.total) * 100;
      let reader = evt.currentTarget;
      //let speed = (evt.loaded - reader.startbt) / (evt.timeStamp - reader.start);
      reader.start = evt.timeStamp;
      reader.startbt = evt.loaded;
      //console.log(reader.id+'/'+reader.count, reader.name, percentLoaded, speed);
    }
  }

  function concatArr2Uint8(s) {
    //Array 2 Uint8Array
    let tmp = [];
    for (let i of s) tmp = tmp.concat(i);
    return new Uint8Array(tmp);
  }

  function Uint8ToBase64(u8Arr, urisafe) {
    //Uint8Array 2 Base64
    let CHUNK_SIZE = 0x8000; //arbitrary number
    let index = 0;
    let length = u8Arr.length;
    let result = "";
    let slice;
    while (index < length) {
      slice = u8Arr.subarray(index, Math.min(index + CHUNK_SIZE, length));
      result += String.fromCharCode.apply(null, slice);
      index += CHUNK_SIZE;
    }
    return urisafe
      ? btoa(result)
          .replace(/\//g, "_")
          .replace(/\+/g, "-")
      : btoa(result);
  }

  function calcEtag() {
    if (!sha1String.length) return "Fto5o-5ea0sNMlW_75VgGJCv2AcJ";
    let sha1Buffer = concatArr2Uint8(sha1String);
    // 如果大于4M，则对各个块的sha1结果再次sha1
    if (blockCount > 1) {
      prefix = 0x96;
      sha1Buffer = shA1(sha1Buffer.buffer);
    } else {
      sha1Buffer = Array.apply([], sha1Buffer);
    }
    sha1Buffer = concatArr2Uint8([[prefix], sha1Buffer]);
    return Uint8ToBase64(sha1Buffer, true);
  }
  return calcEtag();
}

function getChunkSha1(buffer, sliceSize) {
  // sha1算法
  var shA1 = sha1.digest,
    prefix = 0x16,
    blockCount = 0,
    sha1String = [];
  var blockSize = sliceSize | (4 * 1024 * 1024);

  if (buffer) {
    let bufferSize = buffer.size || buffer.length || buffer.byteLength;
    if (blockSize >= bufferSize) {
      blockCount = 1;
      sha1String.push(shA1(buffer));
    } else {
      blockCount = Math.ceil(bufferSize / blockSize);
      for (let i = 0; i < blockCount; i++) {
        sha1String.push(shA1(buffer.slice(i * blockSize, (i + 1) * blockSize)));
      }
    }
  }

  function concatArr2Uint8(s) {
    //Array 2 Uint8Array
    let tmp = [];
    for (let i of s) tmp = tmp.concat(i);
    return new Uint8Array(tmp);
  }

  function Uint8ToBase64(u8Arr, urisafe) {
    //Uint8Array 2 Base64
    let CHUNK_SIZE = 0x8000; //arbitrary number
    let index = 0;
    let length = u8Arr.length;
    let result = "";
    let slice;
    while (index < length) {
      slice = u8Arr.subarray(index, Math.min(index + CHUNK_SIZE, length));
      result += String.fromCharCode.apply(null, slice);
      index += CHUNK_SIZE;
    }
    return urisafe
      ? btoa(result)
          .replace(/\//g, "_")
          .replace(/\+/g, "-")
      : btoa(result);
  }

  function calcEtag() {
    if (!sha1String.length) return "Fto5o-5ea0sNMlW_75VgGJCv2AcJ";
    let sha1Buffer = concatArr2Uint8(sha1String);
    // 如果大于4M，则对各个块的sha1结果再次sha1
    if (blockCount > 1) {
      prefix = 0x96;
      sha1Buffer = shA1(sha1Buffer.buffer);
    } else {
      sha1Buffer = Array.apply([], sha1Buffer);
    }
    sha1Buffer = concatArr2Uint8([[prefix], sha1Buffer]);
    return Uint8ToBase64(sha1Buffer, true);
  }
  return calcEtag();
}
